using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using System.Threading.Tasks;
using System.Net;
using System.Collections.ObjectModel;


namespace VRCPRServer.NetWork
{
    public class SendDataToVR
    {
        private static readonly object lockObj = new object();
        private static SendDataToVR instance;
        private readonly byte heartByte = 0x06;
        private AsyncTcpServer server;
        private AsyncTcpClient vrClent;
        private DataBuffer dataBuffer;

        public static SendDataToVR Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (lockObj)
                    {
                        if (instance == null)
                        {
                            instance = new SendDataToVR();
                        }
                    }
                }
                return instance;
            }
        }

        private SendDataToVR()
        {
            //dataBuffer = new DataBuffer(20480, heartByte, 10);
            InsanceServer();
        }

        /// <summary>
        /// 实例化
        /// </summary>
        private void InsanceServer()
        {

            server = new AsyncTcpServer(IPAddress.Parse(""), 8088);

            server.ClientConnected += new EventHandler<TcpClientConnectedEventArgs>(server_ClientConnected);
            server.ClientDisconnected += new EventHandler<TcpClientDisconnectedEventArgs>(server_ClientDisconnected);
            server.DatagramReceived += new EventHandler<TcpDatagramReceivedEventArgs<byte[]>>(server_DatagramReceived);
            //server.ServertError += new EventHandler<TcpClientNetErrowEventArgs>(server_ServertError);
            server.Start(1);
            Debug.Log("TCP server has been started.");

        }

        /// <summary>
        /// 服务端检测客户端断开连接
        /// </summary>
        /// <param name="sender">服务端</param>
        /// <param name="e">断开连接事件</param>
        private void server_ClientDisconnected(object sender, TcpClientDisconnectedEventArgs e)
        {
            TcpClientState clientState = server.ClientList.FirstOrDefault(item => item.TcpClient.Equals(e.TcpClient));
            Debug.Log(string.Format("TCP client {0} has disconnected.", e.TcpClient.RemoteEndPoint.ToString()));

            if (clientState != null)
            {
                clientState.TcpClient.Close();
                lock (server.ClientList)
                {
                    UnityEngine.Debug.LogError("移除一个客户端");
                    server.ClientList.Remove(clientState);
                }
            }
        }

        /// <summary>
        /// 服务端检测客户端连接
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <param name="e">连接事件</param>
        private void server_ClientConnected(object sender, TcpClientConnectedEventArgs e)
        {
            if (e.TcpClient == null) return;

            string ipaddress = (e.TcpClient.RemoteEndPoint as IPEndPoint).Address.ToString();
            SendStuentInfo();
            Debug.Log(string.Format("TCP client {0} has connected.", e.TcpClient.RemoteEndPoint.ToString()));
        }


        /// <summary>
        /// 服务端接收客户端数据
        /// </summary>
        /// <param name="sender">服务端</param>
        /// <param name="e">接收数据事件</param>
        private void server_DatagramReceived(object sender, TcpDatagramReceivedEventArgs<byte[]> e)
        {
            //Debug.Log(string.Format("Client : {0} --> ", e.TcpClient.RemoteEndPoint.ToString()));
        }

        /// <summary>
        /// 服务端异常报错
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void server_ServertError(object sender, TcpClientNetErrowEventArgs e)
        {
            Debug.LogError(string.Format("ServerError.", e));
        }

        #region
        private void TryConnectPC()
        {
            //string ipAddress = Data.Confige.LocalIP;
            //if (ipAddress == null) return;

            //vrClent = new AsyncTcpClient(IPAddress.Parse(ipAddress), 8088);
            if (vrClent.Connect().IsConnected)
            {
                vrClent.DatagramReceive += TcpClient_DatagramReceive;
                vrClent.ServerConnected += TcpClient_ServerConnected;
                vrClent.ServerDisConnected += TcpClient_ServerDisConnected;
            }
            else
            {
                vrClent.Dispose();
            }
        }


        /// <summary>
        /// 客户端连接上VR服务端
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TcpClient_ServerConnected(object sender, TcpServerConnectedEventArgs e)
        {

            Debug.Log($"客户端连接上PC主机：{e.Addresses[0]} {e.Port}");
        }

        /// <summary>
        /// 客户端断开连接VR服务端
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TcpClient_ServerDisConnected(object sender, TcpServerDisconnectedEventArgs e)
        {
            AsyncTcpClient tcpClient = sender as AsyncTcpClient;
            tcpClient.Dispose();
        }

        /// <summary>
        /// 接收VR服务端数据
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <param name="e">接收数据事件</param>
        private void TcpClient_DatagramReceive(object sender, TcpDatagramReceivedEventArgs<byte[]> e)
        {
            if (e.Datagram == null) return;

            string id = e.TcpClient.RemoteEndPoint.ToString();
            //Factory.NotificationCenter.Get().DispatchEvent(id, new Factory.Notification(e.Datagram));
        }
        #endregion


        private void SendStuentInfo()
        {
            System.Threading.Tasks.Task.Run(() =>
            {
                //ObservableCollection<Models.StudentM> studentMs = MainCanvasVM.Instance.StudentMs;
                //SendSetInfo(Data.Confige.SetConfigM);

                //if (studentMs.Count > 0)
                //{
                //    for (int i = 0; i < studentMs.Count; i++)
                //        SendStuentInfo(MainCanvasVM.Instance.StudentMs[i].StudentInfo);
                //}
            });
        }

        /// <summary>
        /// 发送状态信息（操作状态/连接状态/操作结果）
        /// </summary>
        /// <param name="index"></param>
        public void SendStateInfo(byte order, byte index, byte[] msg)
        {
            byte[] data = new byte[10];
            data[0] = 0x06;
            data[1] = order;
            data[2] = 0x00;
            data[3] = 0X05;
            data[4] = index;
            data[5] = msg[0];
            data[6] = msg[1];
            data[7] = msg[2];
            data[8] = msg[3];

            for (int i = 0; i < data.Length - 1; i++)
                data[9] += data[i];
            SendData(data);
        }


        /// <summary>
        /// 添加操作数据
        /// </summary>
        /// <param name="data"></param>
        /// <param name="index"></param>
        public void AddPressInfo(byte order, byte index, byte[] data)
        {
            // Debug.Log(data[2]);
            if (server.ClientList.Count < 1) return;

            byte[] datas = new byte[10];
            int length = 5;
            datas[0] = 0x06;
            datas[1] = order;
            datas[2] = (byte)(length >> 8);
            datas[3] = (byte)(length & 0xff);
            datas[4] = index;
            Array.Copy(data, 0, datas, 5, 4);

            for (int i = 0; i < data.Length - 1; i++)
                data[9] += data[i];

            dataBuffer.WriteBuffer(datas);
        }

        /// <summary>
        /// 发送学生信息
        /// </summary>
        /// <param name="studentInfo"></param>
        //public void SendStuentInfo(Models.StudentInfo studentInfo)
        //{
        //    if (studentInfo == null) return;

        //    byte[] bytes = SerializeObject.SerializeToBytes(studentInfo);
        //    if (bytes == null) return;

        //    int length = bytes.Length + 6;
        //    int dataLength = bytes.Length + 1;
        //    byte[] datas = new byte[length];
        //    datas[0] = 0x06;
        //    datas[1] = 0x00;
        //    datas[2] = (byte)(dataLength >> 8);
        //    datas[3] = (byte)(dataLength & 0xff);
        //    datas[4] = studentInfo.StudentIndex;
        //    Array.Copy(bytes, 0, datas, 5, bytes.Length);
        //    datas[length - 1] = datas.Sum1(0, length - 1);

        //    SendData(datas);
        //}

        /// <summary>
        /// 发送软件配置信息
        /// </summary>
        /// <param name="studentInfo"></param>
        //public void SendSetInfo(Models.SetConfigM setConfigM)
        //{
        //    if (setConfigM == null) return;

        //    byte[] bytes = SerializeObject.SerializeToBytes(setConfigM);
        //    if (bytes == null) return;

        //    int length = bytes.Length + 6;
        //    int dataLength = bytes.Length + 1;
        //    byte[] datas = new byte[length];
        //    datas[0] = 0x06;
        //    datas[1] = 0x02;
        //    datas[2] = (byte)(dataLength >> 8);
        //    datas[3] = (byte)(dataLength & 0xff);
        //    datas[4] = 0;
        //    Array.Copy(bytes, 0, datas, 5, bytes.Length);
        //    datas[length - 1] = datas.Sum1(0, length - 1);

        //    SendData(datas);
        //}

        private List<byte> datas = new List<byte>();
        public void SendData()
        {
            datas.Clear();
            byte[] data = null;
            //while ((data = dataBuffer.ReadBuffer(10)) != null)
            //{
            //    if (data == null) return;
            //    datas.AddRange(data);
            //}

            SendData(datas.ToArray());
        }

        /// <summary>
        /// 发送心跳包
        /// </summary>
        public void SendHeart()
        {
            SendData(Command.VRHeart);
        }


        public void SendData(byte[] data)
        {
            if (server != null && server.IsRuning && server.ClientList.Count > 0)
                server.SendAll(data);
        }

        public void Close()
        {
            server.Dispose();
        }
    }
}
